<template>
    <div class="files-select">
        <input type="hidden" v-model="selectFile">
        <div class="files-select-input" @click="showFileDialog" :class="getFilesInputClass">
            <div class="files-select-input-placeholder" v-if="isEmpty">
                <div><i class="el-icon-plus"></i></div>
                <div>{{ placeholder }}</div>
            </div>
            <div v-else>
                <div class="files-select-input-list" v-if="multiple">
                    <transition-group name="opacity-translateX" tag="div">
                        <div class="files-select-input-list-item" :style="`width:${size};height:${size};`" v-for="(item,index) in selectFile" :key="item.file_sign">
                            <show-file :file="item" />
                            <div class="files-select-input-list-item-del" v-show="!disabled" @click.stop="delFile(index)">
                                <i class="el-icon-delete"></i>
                            </div>
                        </div>
                    </transition-group>
                </div>
                <div class="files-select-input-list" v-else>
                    <div>
                        <div class="files-select-input-list-item" :style="`width:${size};height:${size};`" :key="selectFile.file_sign">
                            <show-file :file="selectFile" />
                            <div class="files-select-input-list-item-del" v-show="!disabled" @click.stop="delFile(0)">
                                <i class="el-icon-delete"></i>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <p-dialog v-model="showDialog" title="文件选择" :x="pDialogX" :y="pDialogY" width="80%" height="80%">
            <div class="files-select-file">
                <files @select="changeFile" :is-select="true" :multiple="isMmultiple" />
            </div>
        </p-dialog>
    </div>
</template>


<script lang="ts">
import {
    defineComponent,
    reactive,
    toRefs,
    onMounted,
    watch,
    computed,
} from "vue";
import { useStore } from "vuex";
import PDialog from "@/components/PDialog.vue";
import Files from "@/components/file/Files.vue";
import config from "@/config";
import ShowFile from "@/components/file/ShowFile.vue";
import utils from "@/lib/utils";

const defaultData = {
    file_sign: "",
    file_name: "",
    file_ext: "",
};
/**
 * state 数据类型
 */
interface IState {
    pDialogX: string;
    pDialogY: string;
    showDialog: boolean;
    selectFile: any;
    isMmultiple: boolean;
}
export default defineComponent({
    name: "FilesSelect",
    components: { PDialog, Files, ShowFile },
    props: {
        modelValue: {
            type: [Object, Array],
        },
        placeholder: {
            type: String,
            default: "请选择文件",
        },
        size: {
            type: String,
            default: "120px",
        },
        // 是否多选
        multiple: {
            type: Boolean,
            default: false,
        },
        // 是否禁用
        disabled: {
            type: Boolean,
            default: false,
        },
    },
    emits: ["update:modelValue", "change"],
    setup(props, { emit }) {
        const store = useStore();
        const { UIAuth, bodySize } = toRefs(store.state);
        /**
         * 文件服务器
         */
        const fileHost: string = config.fileHost;
        /**
         * 图片文件后缀名
         */
        const imageExt: string[] = config.imageFileExt;
        const state = reactive<IState>({
            pDialogX: "50%",
            pDialogY: "50%",
            showDialog: false,
            selectFile: null,
            isMmultiple: false,
        });
        watch(() => props.modelValue, (val) => state.selectFile = val);
        watch(() => props.multiple, (val) => {
            state.isMmultiple = val;
        });
        onMounted(() => {
            state.selectFile = props.modelValue;
            state.isMmultiple = props.multiple;
        });
        /**
         * 判断是否为空
         */
        const isEmpty = computed(() => {
            if (props.multiple) {
                if (state.selectFile instanceof Array) {
                    return state.selectFile.length === 0;
                } else {
                    return utils.empty(state.selectFile);
                }
            } else {
                return utils.empty(state.selectFile);
            }
        });
        /**
         * 获取class 名
         */
        const getFilesInputClass = computed(() => {
            if (!props.disabled && state.showDialog) {
                return "files-select-input-action files-select-input-hover";
            } else if (!props.disabled && !state.showDialog) {
                return "files-select-input-hover";
            } else {
                return "";
            }
        });
        /**
         * 判断是否时图片文件
         */
        const isImages = (ext: string): boolean => {
            const index = imageExt.findIndex((i: string) => i === ext);
            return index >= 0;
        };

        const appendSelectFile = (file: any) => {
            const index = state.selectFile.findIndex(
                (item: any) => item.file_sign === file.file_sign
            );
            if (index < 0) {
                const temFile = {
                    file_sign: file.file_sign,
                    file_name: file.file_name,
                    file_ext: file.file_ext,
                };
                if (state.selectFile instanceof Array) {
                    state.selectFile.push(temFile);
                } else {
                    state.selectFile = [temFile];
                }
            }
        };

        /**
         * 显示选择文件窗口
         */
        const showFileDialog = (event: MouseEvent) => {
            if (props.disabled) {
                return;
            }
            state.pDialogX = event.clientX + "px";
            state.pDialogY = event.clientY + "px";
            state.showDialog = true;
        };

        /**
         * 选择文件事件
         */
        const changeFile = (files: any) => {
            if (props.multiple) {
                if (files instanceof Array) {
                    files.forEach((item) => appendSelectFile(item));
                } else {
                    appendSelectFile(files);
                }
            } else {
                if (files instanceof Array) {
                    if (files.length > 0) {
                        state.selectFile = {
                            file_sign: files[0].file_sign,
                            file_name: files[0].file_name,
                            file_ext: files[0].file_ext,
                        };
                    } else {
                        state.selectFile = null;
                    }
                } else {
                    state.selectFile = {
                        file_sign: files.file_sign,
                        file_name: files.file_name,
                        file_ext: files.file_ext,
                    };
                }
            }
            state.showDialog = false;
            emit("update:modelValue", state.selectFile);
            emit("change", state.selectFile);
        };

        /**
         * 删除文件
         */
        const delFile = (index: number) => {
            if (props.multiple) {
                if (state.selectFile instanceof Array) {
                    state.selectFile.splice(index, 1);
                } else {
                    state.selectFile = "";
                }
            } else {
                state.selectFile = "";
            }
            emit("update:modelValue", state.selectFile);
            emit("change", state.selectFile);
        };
        return {
            UIAuth,
            bodySize,
            ...toRefs(state),
            fileHost,
            imageExt,
            isEmpty,
            getFilesInputClass,
            isImages,
            showFileDialog,
            changeFile,
            delFile,
        };
    },
});
</script>

<style scoped lang="scss">
.files-select {
    &-input {
        position: relative;
        border: 1px $border-color3 solid;
        padding: 0 10px 10px 0;
        border-radius: 4px;
        transition: all 0.2s;

        &-action {
            border: 1px $primary-color solid;
        }

        &-hover {
            &:hover {
                border: 1px $primary-color solid;
            }
        }

        cursor: pointer;

        &-placeholder {
            display: inline-block;
            min-height: 100px;
            margin-left: 10px;
            margin-top: 10px;
            color: $text-placeholder-color;
            text-align: center;

            & > div {
                :nth-child(1) {
                    margin-top: 20px;
                    font-size: 50px;
                    margin-bottom: 10px;
                }
            }
        }

        &-list {
            & > div {
                position: relative;
                height: 100%;
                display: flex;
                align-content: flex-start;
                flex-wrap: wrap;
            }

            &-item {
                position: relative;
                width: 120px;
                margin-left: 10px;
                margin-top: 10px;
                height: 120px;
                border-radius: 5px;
                overflow: hidden;
                border: 1px $border-color2 solid;
                &-del {
                    position: absolute;
                    right: 0;
                    top: 0;
                    background-color: #d70606;
                    color: #fff;
                    width: 30px;
                    height: 30px;
                    display: flex;
                    justify-content: center;
                    align-items: center;
                    font-size: 18px;
                    transition: all 0.3s ease-in;
                    border-bottom-left-radius: 5px;

                    &:hover {
                        width: 40px;
                        height: 40px;
                        font-size: 22px;
                    }
                }
            }
        }
    }

    &-file {
        padding: 10px;
        height: calc(100% - 20px);
    }
}
</style>
<style lang="scss">
.el-form-item.is-error {
    & .files-select {
        &-input {
            border: 1px $danger-color solid;
        }
    }
}
</style>
